package org.xxkk.util;

import org.json.JSONObject;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.table.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.*;
import java.io.File;
import java.io.FileWriter;
import java.nio.file.Files;
import java.sql.*;
import java.util.*;
import java.util.List;

/**
 * MySQL 表编辑器 · 2025 洁版（永久白天 + 设置面板永不遮挡）
 */
public class MySQLTableEditor extends JFrame {

    private final JTextField hostField = new JTextField("localhost");
    private final JTextField portField = new JTextField("3316");
    private final JTextField dbField = new JTextField("pay_db");
    private final JTextField userField = new JTextField("root");
    private final JPasswordField passField = new JPasswordField("123456");
    private final JTextField tableField = new JTextField("java_pay_server_config");

    private final JButton connectButton = new JButton("连接");
    private final JButton saveButton = new JButton("保存修改");
    private final JButton toggleButton = new JButton("隐藏设置");

    private final JTable table = new JTable();
    private final DefaultTableModel tableModel = new DefaultTableModel();
    private Connection connection;
    private String currentTableName;

    private final Map<String, Vector<Object>> originalData = new HashMap<>();
    private final Set<String> dirtyRows = new HashSet<>();
    private List<String> pkColumns = new ArrayList<>();
    private List<String> allColumns = new ArrayList<>();

    private static final String ORDER_COL = "display_order";
    private boolean isDragging = false;
    private int draggedRow = -1;
    private JPanel configPanel;
    private boolean configVisible = true;

    // 1. 类成员区加这行
    private final JButton reorderIdButton = new JButton("重排 ID");

    // 配置文件路径（放在用户目录，永不丢失）
    private static final String CONFIG_FILE = System.getProperty("user.home") + "/.mysql_editor_config.json";

    public MySQLTableEditor() {
        initUI();
        applyChineseFont();
    }

    private void applyChineseFont() {
        Font f = new Font("微软雅黑", Font.PLAIN, 16);
        Font tf = new Font("微软雅黑", Font.PLAIN, 17);
        Font hf = new Font("微软雅黑", Font.BOLD, 18);

        UIManager.put("Button.font", f);
        UIManager.put("Label.font", f);
        UIManager.put("TextField.font", f);
        UIManager.put("PasswordField.font", f);
        UIManager.put("Table.font", tf);
        UIManager.put("TableHeader.font", hf);
        UIManager.put("MenuItem.font", f);
        UIManager.put("OptionPane.messageFont", f);
        UIManager.put("OptionPane.buttonFont", f);
    }

    private void initUI() {
        setTitle("MySQL 表编辑器 · 洁版");
        setSize(1580, 980);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        // 永久白天背景
        getContentPane().setBackground(Color.WHITE);

        // 顶部栏
        JPanel topBar = new JPanel(new BorderLayout());
        topBar.setBackground(new Color(240, 248, 255));
        topBar.setBorder(new EmptyBorder(18, 28, 18, 28));

        JPanel left = new JPanel(new FlowLayout(FlowLayout.LEFT, 25, 0));
        left.setOpaque(false);
        toggleButton.setPreferredSize(new Dimension(110, 48));
        left.add(toggleButton);

        // 2. initUI() 中加入按钮
        left.add(toggleButton);
        left.add(Box.createHorizontalStrut(20));
        reorderIdButton.setPreferredSize(new Dimension(130, 48));
        reorderIdButton.setEnabled(false);
        left.add(reorderIdButton);

        JPanel right = new JPanel(new FlowLayout(FlowLayout.RIGHT, 25, 0));
        right.setOpaque(false);
        connectButton.setPreferredSize(new Dimension(130, 48));
        saveButton.setPreferredSize(new Dimension(150, 48));
        saveButton.setEnabled(false);
        right.add(saveButton);
        right.add(connectButton);

        topBar.add(left, BorderLayout.WEST);
        topBar.add(right, BorderLayout.EAST);

        // 设置面板（高度拉满，永不遮挡）
        configPanel = createConfigPanel();
        configPanel.setVisible(this.configVisible);

        // 表格
        table.setModel(tableModel);
        table.setRowHeight(50);
        table.setFillsViewportHeight(true);
        table.setShowGrid(true);
        table.setGridColor(new Color(230, 230, 230));
        table.setSelectionBackground(new Color(173, 216, 230));
        table.setSelectionForeground(Color.BLACK);
        table.setForeground(Color.BLACK);
        table.setBackground(Color.WHITE);
        table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
        table.setCellSelectionEnabled(true);

        JTableHeader header = table.getTableHeader();
        header.setBackground(new Color(240, 248, 255));
        header.setForeground(new Color(0, 100, 200));
        header.setPreferredSize(new Dimension(0, 58));

        JScrollPane scroll = new JScrollPane(table);
        scroll.setBorder(BorderFactory.createEmptyBorder());
        scroll.getViewport().setBackground(Color.WHITE);

        // 布局
        setLayout(new BorderLayout());
        add(topBar, BorderLayout.NORTH);
        add(scroll, BorderLayout.CENTER);
        add(configPanel, BorderLayout.SOUTH);

        // 事件
        toggleButton.addActionListener(e -> toggleConfig());
        connectButton.addActionListener(e -> connect());
        saveButton.addActionListener(new SaveListener());

        setVisible(true);
        // === 启动时自动读取上次配置 ===
        loadConfigFromFile();
    }

    // 保存配置到本地文件
    private void saveConfigToFile() {
        try {
            JSONObject json = new JSONObject();
            json.put("host", hostField.getText().trim());
            json.put("port", portField.getText().trim());
            json.put("database", dbField.getText().trim());
            json.put("table", tableField.getText().trim());
            json.put("username", userField.getText().trim());
            json.put("password", new String(passField.getPassword()));

            FileWriter writer = new FileWriter(CONFIG_FILE);
            writer.write(json.toString(2));
            writer.close();
        } catch (Exception e) {
            // 静默失败，不打扰用户
        }
    }

    // 启动时自动读取配置
    private void loadConfigFromFile() {
        try {
            File file = new File(CONFIG_FILE);
            if (!file.exists()) return;

            String content = new String(Files.readAllBytes(file.toPath()));
            JSONObject json = new JSONObject(content);

            hostField.setText(json.optString("host", "localhost"));
            portField.setText(json.optString("port", "3316"));
            dbField.setText(json.optString("database", "pay_db"));
            tableField.setText(json.optString("table", "java_pay_server_config"));
            userField.setText(json.optString("username", "root"));
            passField.setText(json.optString("password", "123456"));

        } catch (Exception e) {
            // 静默失败
        }
    }

    private JPanel createConfigPanel() {
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
        p.setBackground(Color.WHITE);
        p.setBorder(new EmptyBorder(50, 80, 50, 80)); // 上下左右大留白

        JPanel[] rows = {
                new JPanel(new FlowLayout(FlowLayout.LEFT, 40, 22)),
                new JPanel(new FlowLayout(FlowLayout.LEFT, 40, 22)),
                new JPanel(new FlowLayout(FlowLayout.LEFT, 40, 22))
        };
        for (JPanel row : rows) {
            row.setOpaque(false);
            row.setMaximumSize(new Dimension(2000, 82));
            p.add(row);
            p.add(Box.createVerticalStrut(25));
        }

        String[] labels = {"主机地址：", "端口号：", "数据库名：", "表名：", "用户名：", "密码："};
        JTextField[] fields = {hostField, portField, dbField, tableField, userField, passField};

        for (int i = 0; i < labels.length; i++) {
            JLabel l = new JLabel(labels[i]);
            l.setFont(new Font("微软雅黑", Font.PLAIN, 20));
            l.setPreferredSize(new Dimension(110, 56));

            fields[i].setFont(new Font("微软雅黑", Font.PLAIN, 20));
            fields[i].setPreferredSize(new Dimension(360, 66));
            fields[i].setBorder(BorderFactory.createCompoundBorder(
                    BorderFactory.createLineBorder(new Color(180, 180, 180)),
                    BorderFactory.createEmptyBorder(20, 20, 20, 20)
            ));

            rows[i / 2].add(l);
            rows[i / 2].add(fields[i]);
        }

        tableField.addActionListener(e -> connectButton.doClick());

        // 终极锁定：高度 380px 永不变化
        JScrollPane scroll = new JScrollPane(p);
        scroll.setBorder(BorderFactory.createEmptyBorder());
        scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
        scroll.setPreferredSize(new Dimension(Short.MAX_VALUE, 380));
        scroll.setMinimumSize(new Dimension(0, 380));
        scroll.setMaximumSize(new Dimension(Short.MAX_VALUE, 380));

        JPanel wrapper = new JPanel(new BorderLayout());
        wrapper.setBackground(Color.WHITE);
        wrapper.add(scroll, BorderLayout.CENTER);
        return wrapper;
    }

    private void toggleConfig() {
        configVisible = !configVisible;
        configPanel.setVisible(configVisible);
        toggleButton.setText(configVisible ? "隐藏设置" : "设置");
        revalidate();
    }

    // === 连接（强制 UTF-8）===
    private void connect() {
        String url = String.format(
                "jdbc:mysql://%s:%s/%s?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai",
                hostField.getText().trim(), portField.getText().trim(), dbField.getText().trim()
        );

        connectButton.setEnabled(false);
        saveButton.setEnabled(false);

        new Thread(() -> {
            try {
                connection = DriverManager.getConnection(url, userField.getText().trim(), new String(passField.getPassword()));
                currentTableName = tableField.getText().trim();
                loadTable();
                SwingUtilities.invokeLater(() -> connectButton.setEnabled(true));
                // 4. 加上事件
                reorderIdButton.addActionListener(e -> reorderIdSequentially());
                // 连接成功 → 立即保存配置
                SwingUtilities.invokeLater(() -> {
                    saveConfigToFile();
                    connectButton.setEnabled(true);
                });
            } catch (Exception ex) {
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this, "连接失败：\n" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                    connectButton.setEnabled(true);
                });
            }
        }).start();
    }

    // === 加载表格（核心逻辑保持不变）===
    private void loadTable() throws SQLException {
        originalData.clear();
        dirtyRows.clear();
        pkColumns.clear();
        allColumns.clear();

        DatabaseMetaData meta = connection.getMetaData();
        ResultSet rs = meta.getColumns(null, null, currentTableName, null);
        while (rs.next()) allColumns.add(rs.getString("COLUMN_NAME"));
        rs.close();

        rs = meta.getPrimaryKeys(null, null, currentTableName);
        while (rs.next()) pkColumns.add(rs.getString("COLUMN_NAME"));
        rs.close();
        if (pkColumns.isEmpty()) throw new SQLException("无主键");

        if (!allColumns.contains(ORDER_COL)) {
            try (Statement s = connection.createStatement()) {
                s.executeUpdate("ALTER TABLE `" + currentTableName + "` ADD COLUMN `" + ORDER_COL + "` INT DEFAULT 0");
            }
            allColumns.add(ORDER_COL);
        }

        try (Statement s = connection.createStatement()) {
            s.executeUpdate("SET @i=0");
            s.executeUpdate("UPDATE `" + currentTableName + "` SET `" + ORDER_COL + "` = (@i:=@i+10) WHERE `" + ORDER_COL + "` <= 0");
        }

        String sql = "SELECT * FROM `" + currentTableName + "` ORDER BY `" + ORDER_COL + "` ASC";
        PreparedStatement ps = connection.prepareStatement(sql);
        ResultSet dataRs = ps.executeQuery();

        Vector<Vector<Object>> data = new Vector<>();
        while (dataRs.next()) {
            Vector<Object> row = new Vector<>();
            StringBuilder pk = new StringBuilder();
            for (String col : allColumns) {
                Object val = dataRs.getObject(col);
                row.add(val);
                if (pkColumns.contains(col)) {
                    if (pk.length() > 0) pk.append("\t");
                    pk.append(val == null ? "NULL" : val.toString());
                }
            }
            data.add(row);
            originalData.put(pk.toString(), new Vector<>(row));
        }

        SwingUtilities.invokeLater(() -> {
            tableModel.setDataVector(data, new Vector<>(allColumns));
            tableModel.addTableModelListener(e -> {
                if (e.getType() == TableModelEvent.UPDATE && e.getColumn() != -1) {
                    markRowDirty(e.getFirstRow());
                }
            });

            int idx = tableModel.findColumn(ORDER_COL);
            if (idx != -1) table.removeColumn(table.getColumnModel().getColumn(idx));

            JPopupMenu menu = new JPopupMenu();
            JMenuItem edit = new JMenuItem("编辑大文本");
            edit.addActionListener(e -> {
                int r = table.getSelectedRow(), c = table.getSelectedColumn();
                if (r != -1 && c != -1) openTextEditor(r, c);
            });
            JMenuItem copy = new JMenuItem("复制单元格");
            copy.addActionListener(e -> {
                int r = table.getSelectedRow(), c = table.getSelectedColumn();
                if (r != -1 && c != -1) {
                    Object v = table.getValueAt(r, c);
                    Toolkit.getDefaultToolkit().getSystemClipboard()
                            .setContents(new java.awt.datatransfer.StringSelection(v == null ? "" : v.toString()), null);
                }
            });
            menu.add(edit);
            menu.add(copy);
            table.setComponentPopupMenu(menu);

            table.setDragEnabled(true);
            table.setDropMode(DropMode.INSERT_ROWS);
            table.setTransferHandler(new DragHandler());

            table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
                @Override
                public Component getTableCellRendererComponent(JTable t, Object v,
                                                               boolean s, boolean f, int r, int c) {
                    Component comp = super.getTableCellRendererComponent(t, v, s, f, r, c);
                    if (isDragging && r == draggedRow) {
                        comp.setBackground(new Color(173, 216, 230));
                    } else if (!s) {
                        comp.setBackground(Color.WHITE);
                    }
                    return comp;
                }
            });
            saveButton.setEnabled(false);
            // === 主键列居中显示 + 表头加粗居中（JDK 1.8 完美兼容）===
            TableColumnModel columnModel = table.getColumnModel();
            for (int i = 0; i < columnModel.getColumnCount(); i++) {
                TableColumn column = columnModel.getColumn(i);
                String colName = table.getColumnName(i);

                if (pkColumns.contains(colName)) {
                    // 主键列：内容居中
                    DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
                    centerRenderer.setHorizontalAlignment(JLabel.CENTER);
                    column.setCellRenderer(centerRenderer);

                    // 表头：加粗 + 居中
                    TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer();
                    table.getTableHeader().getColumnModel().getColumn(i).setHeaderRenderer((table1, value, isSelected, hasFocus, row, col) -> {
                        JLabel label = (JLabel) headerRenderer.getTableCellRendererComponent(
                                table1, value, isSelected, hasFocus, row, col);
                        label.setHorizontalAlignment(JLabel.CENTER);
                        label.setFont(label.getFont().deriveFont(Font.BOLD));
                        return label;
                    });
                }
            }
        });

        // 3. loadTable() 最后启用
        reorderIdButton.setEnabled(true);
    }

    private void markRowDirty(int row) {
        String pk = buildPK(row);
        if (pk == null) return;
        Vector<Object> cur = getRowData(row);
        Vector<Object> org = originalData.get(pk);
        if (!cur.equals(org)) dirtyRows.add(pk);
        else dirtyRows.remove(pk);
        saveButton.setEnabled(!dirtyRows.isEmpty());
    }

    private String buildPK(int row) {
        StringBuilder sb = new StringBuilder();
        for (String col : pkColumns) {
            int idx = tableModel.findColumn(col);
            if (idx == -1) continue;
            Object v = tableModel.getValueAt(row, idx);
            if (sb.length() > 0) sb.append("\t");
            sb.append(v == null ? "NULL" : v.toString());
        }
        return sb.toString();
    }

    private Vector<Object> getRowData(int row) {
        Vector<Object> v = new Vector<>();
        for (int i = 0; i < tableModel.getColumnCount(); i++) {
            Object val = tableModel.getValueAt(row, i);
            v.add(val == null || (val instanceof String && ((String) val).trim().isEmpty()) ? null : val);
        }
        return v;
    }

    private void openTextEditor(int row, int col) {
        String colName = table.getColumnName(col);
        Object val = table.getValueAt(row, col);
        String text = val == null ? "" : val.toString();

        JTextArea ta = new JTextArea(text, 22, 80);
        ta.setFont(new Font("微软雅黑", Font.PLAIN, 17));
        ta.setLineWrap(true);

        int res = JOptionPane.showOptionDialog(this, new JScrollPane(ta),
                "编辑：" + colName, JOptionPane.OK_CANCEL_OPTION,
                JOptionPane.PLAIN_MESSAGE, null, null, null);

        if (res == JOptionPane.OK_OPTION) {
            String newText = ta.getText().trim();
            table.setValueAt(newText.isEmpty() ? null : newText, row, col);
        }
    }

    // === 一键重排 ID：让主键真正从 1 开始递增 ===
    // 一键重排 ID（极简版 · 主键必自增 · 永不插入）
    private void reorderIdSequentially() {
//        if (JOptionPane.showConfirmDialog(this,
//                "即将永久重排所有记录的 ID！\n" +
//                        "系统会清空表并按当前拖拽顺序重新插入数据\n" +
//                        "所有记录将获得全新的自增 ID（1,2,3...）\n\n是否继续？",
//                "重排 ID", JOptionPane.YES_NO_OPTION,
//                JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION) return;

        reorderIdButton.setEnabled(false);
        saveButton.setEnabled(false);

        new Thread(() -> {
            try {
                connection.setAutoCommit(false);

                // 1. 收集当前所有行数据（含隐藏列）
                Vector<Vector<Object>> data = new Vector<>();
                for (int i = 0; i < tableModel.getRowCount(); i++) {
                    Vector<Object> row = new Vector<>();
                    for (int j = 0; j < tableModel.getColumnCount(); j++) {
                        row.add(tableModel.getValueAt(i, j));
                    }
                    data.add(row);
                }

                // 2. 清空表（TRUNCATE 会重置自增为 1）
                try (Statement s = connection.createStatement()) {
                    s.executeUpdate("TRUNCATE TABLE `" + currentTableName + "`");
                }

                // 3. 构建 INSERT（完全跳过主键列）
                StringBuilder sql = new StringBuilder("INSERT INTO `")
                        .append(currentTableName).append("` (");

                // 所有非主键列
                for (int i = 0; i < allColumns.size(); i++) {
                    String col = allColumns.get(i);
                    if (!pkColumns.contains(col)) {
                        if (sql.toString().endsWith("(")) {
                            sql.append("`").append(col).append("`");
                        } else {
                            sql.append(",`").append(col).append("`");
                        }
                    }
                }
                sql.append(") VALUES (");
                for (int i = 0; i < allColumns.size() - pkColumns.size(); i++) {
                    if (i > 0) sql.append(",");
                    sql.append("?");
                }
                sql.append(")");

                // 4. 批量插入
                try (PreparedStatement ps = connection.prepareStatement(sql.toString())) {
                    for (Vector<Object> row : data) {
                        int paramIndex = 1;
                        for (int i = 0; i < allColumns.size(); i++) {
                            if (!pkColumns.contains(allColumns.get(i))) {
                                ps.setObject(paramIndex++, row.get(i));
                            }
                        }
                        ps.addBatch();
                    }
                    ps.executeBatch();
                }

                connection.commit();

                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this,
                            "重排完成！\n成功插入 " + data.size() + " 条记录\n所有 ID 已完美变为 1,2,3...",
                            "成功", JOptionPane.INFORMATION_MESSAGE);
                    try {
                        loadTable();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                });

            } catch (Exception ex) {
                try {
                    connection.rollback();
                } catch (Exception ignored) {
                }
                ex.printStackTrace();
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(this,
                            "操作失败：\n" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                    reorderIdButton.setEnabled(true);
                    saveButton.setEnabled(true);
                });
            } finally {
                try {
                    connection.setAutoCommit(true);
                } catch (Exception ignored) {
                }
            }
        }).start();
    }

    private class SaveListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (dirtyRows.isEmpty()) return;
            saveButton.setEnabled(false);
            new Thread(() -> {
                int cnt = 0;
                PreparedStatement ps = null;
                try {
                    StringBuilder sql = new StringBuilder("UPDATE `").append(currentTableName).append("` SET ");
                    for (String col : allColumns) {
                        if (!pkColumns.contains(col)) sql.append("`").append(col).append("`=?,");
                    }
                    sql.setLength(sql.length() - 1);
                    sql.append(" WHERE ");
                    for (int i = 0; i < pkColumns.size(); i++) {
                        sql.append("`").append(pkColumns.get(i)).append("`=?");
                        if (i < pkColumns.size() - 1) sql.append(" AND ");
                    }

                    ps = connection.prepareStatement(sql.toString());

                    for (String pk : dirtyRows) {
                        int row = findRowByPk(pk);
                        if (row == -1) continue;
                        int idx = 1;
                        for (String col : allColumns) {
                            if (!pkColumns.contains(col)) {
                                int colIdx = tableModel.findColumn(col);
                                ps.setObject(idx++, tableModel.getValueAt(row, colIdx));
                            }
                        }
                        for (String pkCol : pkColumns) {
                            int colIdx = tableModel.findColumn(pkCol);
                            ps.setObject(idx++, tableModel.getValueAt(row, colIdx));
                        }
                        cnt += ps.executeUpdate();
                        originalData.put(pk, getRowData(row));
                    }
                    dirtyRows.clear();

                    int finalCnt = cnt;
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(MySQLTableEditor.this,
                                "成功保存 " + finalCnt + " 条记录", "完成", JOptionPane.INFORMATION_MESSAGE);
                        saveButton.setEnabled(false);
                    });
                } catch (Exception ex) {
                    ex.printStackTrace();
                    SwingUtilities.invokeLater(() -> {
                        JOptionPane.showMessageDialog(MySQLTableEditor.this,
                                "保存失败：\n" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                        saveButton.setEnabled(true);
                    });
                } finally {
                    if (ps != null) try {
                        ps.close();
                    } catch (Exception ignored) {
                    }
                }
            }).start();
        }

        private int findRowByPk(String pk) {
            for (int i = 0; i < tableModel.getRowCount(); i++) {
                if (pk.equals(buildPK(i))) return i;
            }
            return -1;
        }
    }

    // === 拖拽排序（JDK 1.8 永不报错）===
    private class DragHandler extends TransferHandler {
        private final DataFlavor flavor = new DataFlavor(Object.class, "RowMove");

        @Override
        protected Transferable createTransferable(JComponent c) {
            draggedRow = table.getSelectedRow();
            if (draggedRow == -1) return null;
            isDragging = true;
            table.repaint();
            return new Transferable() {
                @Override
                public DataFlavor[] getTransferDataFlavors() {
                    return new DataFlavor[]{flavor};
                }

                @Override
                public boolean isDataFlavorSupported(DataFlavor f) {
                    return flavor.equals(f);
                }

                @Override
                public Object getTransferData(DataFlavor f) {
                    return draggedRow;
                }
            };
        }

        @Override
        public int getSourceActions(JComponent c) {
            return MOVE;
        }

        @Override
        public boolean canImport(TransferSupport s) {
            return s.isDrop() && s.isDataFlavorSupported(flavor);
        }

        @Override
        public boolean importData(TransferSupport s) {
            if (!canImport(s)) return false;
            int target = ((JTable.DropLocation) s.getDropLocation()).getRow();
            int source = draggedRow;
            if (source == -1 || source == target) {
                endDrag();
                return false;
            }

            try {
                int pos = source < target ? target - 1 : target;
                Vector<Object> row = getRowData(source);
                tableModel.removeRow(source);
                tableModel.insertRow(pos, row);

                int orderIdx = tableModel.findColumn(ORDER_COL);
                for (int i = 0; i < tableModel.getRowCount(); i++) {
                    int newVal = (i + 1) * 10;
                    Object old = tableModel.getValueAt(i, orderIdx);
                    if (!Objects.equals(newVal, old)) {
                        tableModel.setValueAt(newVal, i, orderIdx);
                        markRowDirty(i);
                    }
                }
                table.setRowSelectionInterval(pos, pos);
                return true;
            } finally {
                endDrag();
            }
        }

        @Override
        protected void exportDone(JComponent c, Transferable t, int action) {
            endDrag();
        }

        private void endDrag() {
            isDragging = false;
            draggedRow = -1;
            table.repaint();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getLookAndFeel());
            } catch (Exception ignored) {
            }
            new MySQLTableEditor();
        });
    }
}